﻿using System;
using System.IO;
using System.Net.Sockets;
using UnityEngine;
using UnityEngine.Networking;

public class NetWorkManager:Singleton<NetWorkManager>
{

    public NetWorkManager()
    {
        m_client = new TcpClient();
        m_memoryStream = new MemoryStream();
        m_reader = new BinaryReader(m_memoryStream);
    }

    //是否连接状态
    public bool Connedted
    {
        get
        {
            return (m_client != null && m_client.Connected);
        }
    }


    //发起登陆链接
    public void Login()
    {
        ProtoBuf.Login.RequestLogin login = ProtoBuf.Login.RequestLogin.CreateBuilder()
            .SetParam("login,test!")
            .Build();

        byte[] msg = login.ToByteArray();
        ByteBuffer buff = new ByteBuffer();
        buff.WriteUInt32(100);
        buff.WriteUInt32((UInt32)msg.Length);
        buff.WriteBytes(msg,false);

        SendMessage(buff.ToBytes());
       
        //loginNet.ConnectServer(ip, port, () =>
        //{
        //    Debugger.Log("loginNet connet success");
        //    //链接成功后 发送登陆指令
        //    LoginParams loginParam = new LoginParams();
        //    loginParam.deviceId = deviceID;
        //    loginParam.channel = channelID;
        //    loginParam.appVer = Module.StartUp.Vo.VersionInfo.Instance().m_dllVersion_Local;
        //    loginParam.res = Module.StartUp.Vo.VersionInfo.Instance().m_assetVersion_Local;

        //    loginParam.model = model;
        //    loginParam.mfr = "mfrXXX";
        //    loginParam.netType = netType;
        //    loginParam.carrier = "carrierXXX";
        //    loginParam.mapParams = new List<SSMapUnit>();
        //    loginParam.mapParams.Add(SSMapUnit.create("pf", channelID));
        //    loginParam.mapParams.Add(SSMapUnit.create("adfrom", adFrom));
        //    loginParam.mapParams.Add(SSMapUnit.create("block-net", block_net));
        //    loginParam.mapParams.Add(SSMapUnit.create("c-dll", Module.StartUp.Vo.VersionInfo.Instance().m_dllVersion_Local));
        //    loginParam.mapParams.Add(SSMapUnit.create("c-asset", Module.StartUp.Vo.VersionInfo.Instance().m_assetVersion_Local));
        //    loginParam.mapParams.Add(SSMapUnit.create("server_zoneid", serverNumber));
        //    //链接成功后 发送登陆指令
        //    loginProt.send_AdminLoginVerifyReq(StringUtil.AppendFormat("userid={0}&token={1}", AccountData.Instance.UserId, AccountData.Instance.Token), loginParam);
        //},
        //() =>
        //{
        //    LoginPanelController.Model.IsConnectFail = true;
        //});
        //HcProfiler.EndSample();
    }

    /// <summary>
    /// 连接服务端
    /// </summary>
    /// <param name="host"></param>
    /// <param name="port"></param>
    /// <param name="fun"></param>
    /// <param name="onConnectFailCallBack"></param>
    /// <returns></returns>
    public bool ConnectServer(string host, int port)
    {
        Debug.Log(string.Format("host = {0} port = {1}", host, port));
        m_client = null;
        m_client = new TcpClient(AddressFamily.InterNetwork);
        m_client.SendTimeout = 1000;
        m_client.ReceiveTimeout = 1000;
        m_client.NoDelay = true;
        try
        {
            m_client.BeginConnect(host, port, new AsyncCallback(OnConnect), null);
        }
        catch (Exception e)
        {
            Close();
            Debug.Log(e.Message);
        }
        return true;
    }

    /// <summary>
    /// 连接上服务器
    /// </summary>
    void OnConnect(IAsyncResult asr)
    {
        if (m_client.Connected)
        {
            m_netStream = m_client.GetStream();
            m_client.GetStream().BeginRead(m_byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null);
            EventProcess.Dispatch(Notify.NetWork_ConnectSuccess);
        }
        else
        {
            EventProcess.Dispatch(Notify.NetWork_ConnectFail);
        }
    }

    /// <summary>
    /// 读取消息
    /// </summary>
    void OnRead(IAsyncResult asr)
    {
        int bytesRead = 0;
        try
        {
            lock (m_client.GetStream())
            {         
                //读取字节流到缓冲区
                bytesRead = m_client.GetStream().EndRead(asr);
            }
            if (bytesRead < 1) //如果没有字节
            {
                //服务器主动断开链接
                EventProcess.Dispatch(Notify.NetWork_Disconnect);
                return;
            }
            OnReceive(m_byteBuffer, bytesRead);   //分析数据包内容，抛给逻辑层
            lock (m_client.GetStream())
            {         
                //分析完，再次监听服务器发过来的新消息
                Array.Clear(m_byteBuffer, 0, m_byteBuffer.Length);   //清空数组
                m_client.GetStream().BeginRead(m_byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null);
            }
        }
        catch (Exception ex)
        {
            //数据流异常，断开连接
            Debug.Log(ex.Message);
            EventProcess.Dispatch(Notify.NetWork_ByteError);
        }
    }


    void OnReceive(byte[] bytes, int length)
    {
        Debug.LogError("读包" + length);
        m_memoryStream.Seek(0, SeekOrigin.End);
        m_memoryStream.Write(bytes, 0, length);
        //Reset to beginning
        m_memoryStream.Seek(0, SeekOrigin.Begin);
        long totalLen = 0;
        while ((totalLen = m_memoryStream.Length - m_memoryStream.Position) >= m_headCount) //包头6个字节=数据包长度（2个字节）+（协议头4个字节）
        {
            //读四个字节协议头
            UInt32 msgId = m_reader.ReadUInt32();
            //读四个字节协议体长度
            UInt32 bodyLength = m_reader.ReadUInt32();

            uint protUInt32ID = 0;
            long remainLen = m_memoryStream.Length - m_memoryStream.Position;
            if (remainLen >= bodyLength) //消息体够不够
            {
                //协议头 
                //protUInt32ID = Converter.GetLittleEndian(m_reader.ReadUInt32());
                //协议体
                ParserPacket(msgId, m_reader.ReadBytes((int)bodyLength));
            }
            else
            {
                //如果数据长度不匹配回滚字节指针索引
                m_memoryStream.Position = 0;
                break;
            }
        }
        //多余字节
        byte[] leftover = m_reader.ReadBytes((int)RemainingBytes());
        m_memoryStream.SetLength(0);     
        m_memoryStream.Write(leftover, 0, leftover.Length);
    }

    /// <summary>
    /// 剩余的字节
    /// </summary>
    private long RemainingBytes()
    {
        return m_memoryStream.Length - m_memoryStream.Position;
    }

    /// <summary>
    /// 关闭链接
    /// </summary>
    public void Close()
    {
        if (m_client != null)
        {
            if (m_client.Connected) m_client.Close();
            m_client = null;
        }
        EventProcess.Dispatch(Notify.NetWork_ConnectFail);
    }

    /// <summary>
    /// 解析字节流
    /// </summary>
    /// <param name="protID">协议ID</param>
    /// <param name="ms">数据包信息</param>
    void ParserPacket(uint protID, byte[] message)
    {

        if(protID == 100)
        {
            ProtoBuf.Login.RecLogin b = ProtoBuf.Login.RecLogin.ParseFrom(message);

            Debug.LogError(b.UserName);
            Debug.LogError(b.Level);
        }

        //try
        //{
        //    //Debugger.Log("##2 ms.Length - ms.Position: " + (ms.Length - ms.Position) + ", protID:" + protID);
        //    //BinaryReader r = new BinaryReader(ms);
        //    //byte[] message = r.ReadBytes((int)(ms.Length - ms.Position));
        //    Protocol.ByteBuffer buffer = new Protocol.ByteBuffer(message);
        //    Protocol.DataPacket packet = new Protocol.DataPacket(buffer);
        //    packet.protUInt32Id = protID;
        //    netHandler.Process(packet);
        //}
        //catch (Exception ex)
        //{

        //    uint _protId = (protID & 0x00ff00) >> 8;
        //    uint _funcId = (protID & 0xff000000) >> 24;
        //    ProtocolBase protocol;
        //    if (netHandler._dictId2Protocol.TryGetValue((int)_protId, out protocol))
        //    {
        //        Debugger.LogError(protocol.ToString() + "出错了 function id " + _funcId);
        //    }
        //    Debugger.LogError("OnReceivedMessage--->>>协议ID:" + protID + "  错误信息：" + ex.Message + " protID:" + _protId + " functionID:" + _funcId);
        //}
    }

    /// <summary>
    /// 向服务器发送数据包
    /// </summary>
    public bool SendMessage(byte[] buffer)
    {
        if (!Connedted)
        {
            return false;
        }
        WriteMessage(buffer);
        return true;
    }

    /// <summary>
    /// 写入数据包
    /// </summary>
    /// <param name="message"></param>
    private void WriteMessage(byte[] message)
    {
        if (Connedted)
        {
            m_netStream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null);
        }

        //MemoryStream ms = null;
        //using (ms = new MemoryStream())
        //{
        //    ms.Position = 0;
        //    BinaryWriter writer = new BinaryWriter(ms);
        //    ushort msglen = (ushort)(message.Length - 4);
        //    writer.Write(msglen);
        //    writer.Write(message);
        //    writer.Flush();
        //    if (m_client != null && m_client.Connected)
        //    {
        //        //NetworkStream stream = client.GetStream(); 
        //        byte[] payload = ms.ToArray();
        //        m_memoryStream.BeginWrite(payload, 0, payload.Length, new AsyncCallback(OnWrite), null);
        //    }
        //    else
        //    {
        //        Debug.LogError("写入失败!");
        //    }
        //}
    }

    private void OnWrite(IAsyncResult r)
    {
        try
        {
            m_netStream.EndWrite(r);
        }
        catch (Exception ex)
        {
            Debug.LogError("OnWrite--->>>" + ex.Message);
        }
    }

    //数据包缓冲区
    private const int MAX_READ = 8192;
    private byte[] m_byteBuffer = new byte[MAX_READ];
    //tcp客户端
    private TcpClient m_client = null;
    private MemoryStream m_memoryStream = null;
    private BinaryReader m_reader = null;
    private NetworkStream m_netStream = null;
    //包头长度 8个字节，  包长2个字节(65535) 协议头四个字节 （二个字节理论上应该也足够）
    private int m_headCount = 8;

}
